﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using BobcatUtility;
using System.Runtime.Serialization;
using CNStreaming;
using System.IO;
using CNUtility;

namespace CNShapes
{
    /// <summary>
    /// Base class for the different shape classes that can be drawn and shown in
    /// the collaborative-notepad application.
    /// </summary><remarks>
    /// All shapes have:
    /// - A unique string ID
    /// - The shape's rectangular bounds (to help with rendering)
    /// - A version number. This will be updated if changes are made to the shape. 
    ///   Again this is to help with rendering.
    /// </remarks>
    public abstract class Shape : IStreamable
    {
        #region Events

        /// <summary>
        /// Args raised with events from this class.
        /// </summary>
        public class Args : EventArgs
        {
            public Args(ActionOrigin actionOrigin)
            {
                ActionOrigin = actionOrigin;
            }
            public ActionOrigin ActionOrigin { get; set; }
        }

        /// <summary>
        /// Event raised when the shape has been edited.
        /// </summary>
        public event EventHandler<Args> ShapeEditedEvent;

        /// <summary>
        /// Function to be able to raise the event from derived classes.
        /// </summary>
        protected void raiseShapeEditedEvent(ActionOrigin actionOrigin)
        {
            Utility.raiseEvent(ShapeEditedEvent, this, new Args(actionOrigin));
        }

        /// <summary>
        /// Event raised when editing has finished on a shape. (Usually raised
        /// when an input action has completed.)
        /// </summary>
        public event EventHandler<Args> ShapeEditCompletedEvent;

        /// <summary>
        /// Function to raise the edit-completed event from derived classes.
        /// </summary>
        protected void raiseShapeEditCompletedEvent(ActionOrigin actionOrigin)
        {
            Utility.raiseEvent(ShapeEditCompletedEvent, this, new Args(actionOrigin));
        }

        #endregion

        #region Public properties

        /// <summary>
        /// Property to get the ID for this shape.
        /// </summary>
        public Guid ID 
        {
            get { return m_ID; }
        }

        #endregion

        #region IStreamable Members

        /// <summary>
        /// Serializes this class's data to the stream passed in.
        /// </summary>
        public virtual void toStream(MessageStream stream)
        {
            stream.writeGUID(m_ID);
        }

        /// <summary>
        /// Reads this object's data from the stream passed in.
        /// </summary>
        public virtual void fromStream(MessageStream stream, int iVersion)
        {
            m_ID = stream.readGUID();
        }

        public abstract int getMessageVersion();

        #endregion

        #region Abstract methods

        /// <summary>
        /// Returns the shape's bounds in "shape space". A Graphics object is passed
        /// in as some shapes (such as text) do not know how big they are without
        /// knowing how they would be rendered.
        /// </summary>
        public abstract RectangleF getBounds(Graphics graphics);

        #endregion

        #region Public methods

        /// <summary>
        /// Constructor.
        /// </summary>
        public Shape()
        {
            m_ID = Guid.NewGuid();
        }

        /// <summary>
        /// Called (for example by an editing action) when editing a shape has completed.
        /// </summary>
        public void editCompleted(ActionOrigin actionOrigin)
        {
            raiseShapeEditCompletedEvent(actionOrigin);
        }

        #endregion

        #region Private data

        // Unique ID for this shape...
        private Guid m_ID;

        #endregion
    }
}
